package business;

import java.io.FileInputStream;
import java.lang.reflect.Proxy;
import java.util.Properties;

import logging.LogHandler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import persistence.DAOFactory;
import persistence.DAOFactoryJdbcImpl;
import persistence.Subscription;
import business.validation.BusinessValidatorImpl;

public class BusinessObjectAssembler {
	private static DAOFactory daoFactory;
	private static Logger logger = LoggerFactory.getLogger(BusinessObjectAssembler.class);
	
	public static void setDaoFactory(DAOFactory _daoFactory) {
		daoFactory = _daoFactory;
	}
	
	/* configurable factory - code taken from http://openbook.galileocomputing.de/oop/oop_kapitel_07_002.htm#mjc5cb28a57eeadedfbc991e6786b00788 */
	static {
		/* Before, initDAOFactory loaded DAOFactoryImpl from config file, and threw an
		 * Exception so that the client (currently managed bean) may react properly, 
		 * if the DAOFactoryImpl couldn't be loaded -> now, already here in
		 * case of an exception a default implementation is loaded and logged. 
		 */
		if (daoFactory == null) {
			try {
				Properties properties = new Properties();
				properties.load(new FileInputStream("dao.properties"));
				String factoryImpl = properties.getProperty("factory.impl");
				Class<?> factoryImplClass = Class.forName(factoryImpl); //use wildcard type to avoid compiler warning
				daoFactory = (DAOFactory)factoryImplClass.getConstructor(String.class).newInstance("dao.properties");
			}
			catch (Exception ex) {
				daoFactory = createDefaultDAOFactoryImpl();
				logger.debug("DAOFactoryImpl couldn't be loaded. Using default implementation {}", daoFactory.getClass().getName());
			}
		}
	}
	
	private static DAOFactory createDefaultDAOFactoryImpl() {
		return new DAOFactoryJdbcImpl();
	}
	
	public static SubscriptionLogic getSubscriptionLogic() {
		//could instead be loaded from config file
		SubscriptionLogicImpl subscriptionLogic = new SubscriptionLogicImpl();
		subscriptionLogic.setSubscriptionDAO(daoFactory.getSubscriptionDAO());
		subscriptionLogic.setPredefinedEntryDAO(daoFactory.getPredefinedEntryDAO());
		subscriptionLogic.setPredefinedParamDAO(daoFactory.getPredefinedParamDAO());
		subscriptionLogic.setCostUnitDAO(daoFactory.getCostUnitDAO());
		subscriptionLogic.setPurchaserDAO(daoFactory.getPurchaserDAO());
		subscriptionLogic.setSupplierDAO(daoFactory.getSupplierDAO());
		subscriptionLogic.setUserManager(getUserManager());
		subscriptionLogic.setCommonLogic(getCommonLogic());
		
		subscriptionLogic.setBusinessValidator(new BusinessValidatorImpl<Subscription>());
		
		SubscriptionLogic subscriptionLogicProxy = (SubscriptionLogic) getProxy(subscriptionLogic, SubscriptionLogic.class);
		return subscriptionLogicProxy;
	}
	
	public static PeriodicalLogic getPeriodicalLogic() {
		PeriodicalLogic periodicalLogic = new PeriodicalLogicImpl();
		periodicalLogic.setPeriodicalDAO(daoFactory.getPeriodicalDAO());
		periodicalLogic.setCommonLogic(getCommonLogic());
		
		PeriodicalLogic periodicalLogicProxy = (PeriodicalLogic) getProxy(periodicalLogic, PeriodicalLogic.class);
		return periodicalLogicProxy;
	}
	
	public static UserManager getUserManager() {
		UserManager userManager = new UserManagerImpl();
		userManager.setUserDAO(daoFactory.getUserDAO());
		
		UserManager userManagerProxy = (UserManager) getProxy(userManager, UserManager.class);
		return userManagerProxy;		
	}
	
	public static CommonLogic getCommonLogic() {
		CommonLogic commonLogic = new CommonLogicImpl();
		commonLogic.setLibraryLocationDAO(daoFactory.getLibraryLocationDAO());
		commonLogic.setPredefinedParamDAO(daoFactory.getPredefinedParamDAO());
		commonLogic.setPredefinedEntryDAO(daoFactory.getPredefinedEntryDAO());
		
		CommonLogic commonLogicProxy = (CommonLogic) getProxy(commonLogic, CommonLogic.class);	 	
		return commonLogicProxy;
	}
	
	private static Object getProxy(Object businessObject, Class iface) {
		LogHandler logHandler = new LogHandler(businessObject);
		Class interfaces[] = new Class[]{iface};
		return Proxy.newProxyInstance(businessObject.getClass().getClassLoader(), interfaces, logHandler);
	}
}